<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<HTML>
<HEAD>
<LINK REL=STYLESHEET TYPE="text/css" HREF="../../stylesheet.css" TITLE="Style">
<META NAME="GENERATOR" CONTENT="Java2HTML Version 1.5">
<TITLE>czestmyr.jjsched.StringMatcher (Java2HTML)</TITLE>
</HEAD>
<BODY><TABLE id="Header" border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td colspan="2" width="33%">&nbsp;</td>
<td align="center" colspan="2" width="33%">
<font size="4">StringMatcher.java</font>
</td>
<td align="right" colspan="2" width="33%">&nbsp;</td>
</tr>
</TABLE>
<pre ID="Classes">
<A NAME="1"></A><FONT ID="MultiLineComment">/*  This file is a part of JJSched source code
<A NAME="2"></A>    JJSched - Java Jabber Scheduler - a simple Jabber scheduling application
<A NAME="3"></A>    Copyright (C) 2008 Cestmir "CZestmyr" Houska
<A NAME="4"></A>
<A NAME="5"></A>    This program is free software: you can redistribute it and/or modify
<A NAME="6"></A>    it under the terms of the GNU General Public License as published by
<A NAME="7"></A>    the Free Software Foundation, either version 3 of the License, or
<A NAME="8"></A>    (at your option) any later version.
<A NAME="9"></A>
<A NAME="10"></A>    This program is distributed in the hope that it will be useful,
<A NAME="11"></A>    but WITHOUT ANY WARRANTY; without even the implied warranty of
<A NAME="12"></A>    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
<A NAME="13"></A>    GNU General Public License for more details.
<A NAME="14"></A>
<A NAME="15"></A>    You should have received a copy of the GNU General Public License
<A NAME="16"></A>    along with this program.  If not, see &lt;http://www.gnu.org/licenses/&gt; */</FONT>
<A NAME="17"></A>
<A NAME="18"></A><FONT ID="Package">package</FONT> czestmyr.jjsched;
<A NAME="19"></A>
<A NAME="20"></A><FONT ID="Import">import</FONT> java.text.*;
<A NAME="21"></A><FONT ID="Import">import</FONT> java.io.*;
<A NAME="22"></A>
<A NAME="23"></A><FONT ID="FormalComment">/**
<A NAME="24"></A> * Matches a string to an other string and returnes the number that belongs to the matched string.
<A NAME="25"></A> *
<A NAME="26"></A> * This allows for using strings in switch statements without having to iterate over the string many times.
<A NAME="27"></A> * Works only for english alphabet strings. Also, all strings are converted to lowercase before matching.
<A NAME="28"></A> */</FONT>
<A NAME="29"></A><FONT ID="Public">public</FONT> <FONT ID="Class">class</FONT> StringMatcher&lt;V&gt; {
<A NAME="30"></A>    StringMatcher() {
<A NAME="31"></A>        root = <FONT ID="New">new</FONT> TrieNode();
<A NAME="32"></A>    }
<A NAME="33"></A>
<A NAME="34"></A>    <FONT ID="FormalComment">/**
<A NAME="35"></A>     * Adds a string with its ID number to the list of matches
<A NAME="36"></A>     *
<A NAME="37"></A>     * @param   value       ID of the match (should be positive because non-positive IDs are reserved
<A NAME="38"></A>     *                      for indication of not being able to find a match)
<A NAME="39"></A>     * @param   string      The actual match. I.e. while matching later, the string should equal to
<A NAME="40"></A>     *                      this to be matched.
<A NAME="41"></A>     */</FONT>
<A NAME="42"></A>    <FONT ID="Public">public</FONT> <FONT ID="Void">void</FONT> addMatch(V value, String string) {
<A NAME="43"></A>        String lcString = string.toLowerCase();
<A NAME="44"></A>
<A NAME="45"></A>        StringCharacterIterator it = <FONT ID="New">new</FONT> StringCharacterIterator(lcString);
<A NAME="46"></A>        TrieNode node = root;
<A NAME="47"></A>
<A NAME="48"></A>        <FONT ID="SingleLineComment">//Traverse the trie and create new nodes as necessary
<A NAME="49"></A></FONT>        <FONT ID="For">for</FONT> (<FONT ID="Char">char</FONT> c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
<A NAME="50"></A>            node = node.createSibling(c);
<A NAME="51"></A>            <FONT ID="If">if</FONT> (node == <FONT ID="Null">null</FONT>) <FONT ID="Return">return</FONT>; <FONT ID="SingleLineComment">//createSibling could fail in case of incorrect input
<A NAME="52"></A></FONT>        }
<A NAME="53"></A>
<A NAME="54"></A>        node.data = (Object)value;
<A NAME="55"></A>    }
<A NAME="56"></A>
<A NAME="57"></A>    <FONT ID="FormalComment">/**
<A NAME="58"></A>     * Returns an ID of the string
<A NAME="59"></A>     *
<A NAME="60"></A>     * @param   string      The input string that will be matched with the list of matches
<A NAME="61"></A>     * @return              ID of the match that was added with the {@link #addMatch(V, String) addMatch} method.
<A NAME="62"></A>     *                      Zero if no match could be found
<A NAME="63"></A>     */</FONT>
<A NAME="64"></A>    @SuppressWarnings(value={<FONT ID="StringLiteral">"unchecked"</FONT>})
<A NAME="65"></A>    <FONT ID="Public">public</FONT> V match(String string) {
<A NAME="66"></A>        String lcString = string.toLowerCase();
<A NAME="67"></A>
<A NAME="68"></A>        StringCharacterIterator it = <FONT ID="New">new</FONT> StringCharacterIterator(lcString);
<A NAME="69"></A>        TrieNode node = root;
<A NAME="70"></A>
<A NAME="71"></A>        <FONT ID="SingleLineComment">//Traverse the trie without creating new nodes
<A NAME="72"></A></FONT>        <FONT ID="For">for</FONT> (<FONT ID="Char">char</FONT> c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
<A NAME="73"></A>            node = node.getSibling(c);
<A NAME="74"></A>            <FONT ID="If">if</FONT> (node == <FONT ID="Null">null</FONT>) <FONT ID="Return">return</FONT> <FONT ID="Null">null</FONT>; <FONT ID="SingleLineComment">//Fail if ended in a dead-end
<A NAME="75"></A></FONT>        }
<A NAME="76"></A>
<A NAME="77"></A>        <FONT ID="Return">return</FONT> (V)node.data;
<A NAME="78"></A>    }
<A NAME="79"></A>
<A NAME="80"></A>    <FONT ID="Private">private</FONT> TrieNode root;
<A NAME="81"></A>}
<A NAME="82"></A>
<A NAME="83"></A><FONT ID="Class">class</FONT> TrieNode {
<A NAME="84"></A>    TrieNode() {
<A NAME="85"></A>        siblings = <FONT ID="New">new</FONT> TrieNode[<FONT ID="IntegerLiteral">26</FONT>];
<A NAME="86"></A>    }
<A NAME="87"></A>
<A NAME="88"></A>    <FONT ID="Public">public</FONT> TrieNode createSibling(<FONT ID="Char">char</FONT> c) {
<A NAME="89"></A>        TrieNode ret = getSibling(c);
<A NAME="90"></A>        <FONT ID="If">if</FONT> (ret == <FONT ID="Null">null</FONT>) {
<A NAME="91"></A>            ret = <FONT ID="New">new</FONT> TrieNode();
<A NAME="92"></A>            setSibling(c, ret);
<A NAME="93"></A>        }
<A NAME="94"></A>        <FONT ID="Return">return</FONT> ret;
<A NAME="95"></A>    }
<A NAME="96"></A>
<A NAME="97"></A>    <FONT ID="Public">public</FONT> TrieNode getSibling(<FONT ID="Char">char</FONT> c) {
<A NAME="98"></A>        <FONT ID="Int">int</FONT> pos = c - <FONT ID="CharacerLiteral">'a'</FONT>;
<A NAME="99"></A>        <FONT ID="If">if</FONT> (pos &lt; <FONT ID="IntegerLiteral">0</FONT> || pos &gt;= <FONT ID="IntegerLiteral">26</FONT>)
<A NAME="100"></A>            <FONT ID="Return">return</FONT> <FONT ID="Null">null</FONT>;
<A NAME="101"></A>        <FONT ID="Else">else</FONT> <FONT ID="Return">return</FONT> siblings[pos];
<A NAME="102"></A>    }
<A NAME="103"></A>
<A NAME="104"></A>    <FONT ID="Public">public</FONT> <FONT ID="Void">void</FONT> setSibling(<FONT ID="Char">char</FONT> c, TrieNode newValue) {
<A NAME="105"></A>        <FONT ID="Int">int</FONT> pos = c - <FONT ID="CharacerLiteral">'a'</FONT>;
<A NAME="106"></A>        <FONT ID="If">if</FONT> (pos &lt; <FONT ID="IntegerLiteral">0</FONT> || pos &gt;= <FONT ID="IntegerLiteral">26</FONT>)
<A NAME="107"></A>            <FONT ID="Return">return</FONT>;
<A NAME="108"></A>        siblings[pos] = newValue;
<A NAME="109"></A>    }
<A NAME="110"></A>
<A NAME="111"></A>    <FONT ID="Public">public</FONT> Object data;
<A NAME="112"></A>
<A NAME="113"></A>    <FONT ID="Private">private</FONT> TrieNode siblings[];
<A NAME="114"></A>}
<A NAME="115"></A>
<A NAME="116"></A></pre>
</BODY>
</HTML>